//
//  JFSocketRocketInstance.m
//  JFBase
//
//  Created by Alan Wang on 2018/11/15.
//  Copyright © 2018 Alan Wang. All rights reserved.
//

#import "JFSocketRocketInstance.h"
#import "JFDataParserHelper.h"
#import "JFCacheManager.h"
#import "JFResultVo.h"
#import "JFLogHelper.h"
#if __has_include(<SocketRocket/SocketRocket.h>)
#import <SocketRocket/SocketRocket.h>
#else
#import "SocketRocket.h"
#endif
#import "NSDictionary+JSONString.h"
#import "JFNetCheck.h"

@interface JFSocketRocketInstance()<SRWebSocketDelegate>
@end

@implementation JFSocketRocketInstance{
    //缓存websocket
    NSMutableDictionary *_requestQueue;
    //缓存baseUri 的解析类
    NSMutableDictionary *_dataParserQueue;
    //缓存那些socket在重连
    NSMutableDictionary *_reconnectQueue;
    //缓存每个功能号的回调
    NSMutableDictionary *_backQueue;
    //缓存socket未连接 等待连接成功后发送的数据
    NSMutableDictionary *_bakData;
    //网络监测的类
    JFNetCheck * _netcheck;
}
+(instancetype )shareInstance
{
    static dispatch_once_t once;
    static id instance;
    dispatch_once(&once, ^{
        instance = [[self alloc]init];
    });
    return instance;
}

-(id)init
{
    self = [super init];
    if (self)
    {
        _requestQueue=[[NSMutableDictionary alloc] init];
        _dataParserQueue=[[NSMutableDictionary alloc] init];
        _backQueue = [[NSMutableDictionary alloc] init];
        _reconnectQueue = [[NSMutableDictionary alloc] init];
        _bakData = [[NSMutableDictionary alloc] init];
        
        
        
        _netcheck = [[JFNetCheck alloc] init];
        AWWeakSelf(self)
        [_netcheck netStatus:^(NetStatus status) {
            switch (status) {
                case NetStatus_Unknown:
                case NetStatus_NotReachable:
                    break;
                case NetStatus_ReachableViaWWAN:
                case NetStatus_ReachableViaWiFi:{//有网的情况下重连请求
                    [weakself reconnectWebStockt];
                 }break;
                default:
                    break;
            }
        }];
        
    }
    return self;
}

-(void)reconnectWebStockt{
    for (SRWebSocket * webSocket in _requestQueue.allValues) {
        if(!(webSocket.readyState == SR_OPEN)){
            [webSocket open];
        }
    }
}
-(void)invoke:(JFRequestVo *)reqParamVo callBack:(JFCallBack)callback{
    [super invoke:reqParamVo callBack:callback];
    SRWebSocket * websocket = [self creatWebSocket:reqParamVo.baseUri];
    NSString * dataParser = reqParamVo.dataparserServiceName;
    if(dataParser){
        _dataParserQueue[reqParamVo.baseUri] = dataParser;
    }
    if(callback&&reqParamVo.flowNo){
        _backQueue[reqParamVo.flowNo] = callback;
    }
    
    if(websocket.readyState == SR_OPEN){
         if(reqParamVo.reqParam){//发送数据
            [websocket send:[reqParamVo.reqParam JSONPrintedString]];
         }
    }else{
        if(websocket.readyState == SR_CONNECTING){
          [websocket open];
        }
        if(reqParamVo.flowNo){
            _bakData[reqParamVo.flowNo] = reqParamVo;
        }
        
    }

}
-(SRWebSocket*)creatWebSocket:(NSString*)url{
    if(url){
        SRWebSocket * websocket = _requestQueue[url];
        if(!websocket){
            websocket = [[SRWebSocket alloc] initWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
            websocket.delegate = self;
            _requestQueue[url] = websocket;
        }
        if(websocket.readyState == SR_CONNECTING){
            [websocket open];
        }
        return websocket;
    }else{
        return nil;
    }
}
-(void)cancelAllRequest{
    if (_requestQueue) {
        //取消所有的请求
        for (NSString* baseUrl in _requestQueue.allKeys) {
            [self removeObjectByKey:baseUrl];
        }
        [_requestQueue removeAllObjects];
        [_backQueue removeAllObjects];
        [_bakData removeAllObjects];
        [_dataParserQueue removeAllObjects];
        [_reconnectQueue removeAllObjects];
    }
}

- (void)clearAllRequest{
    [self cancelAllRequest];
}
-(void)clearRequest:(NSString *)flowNo baseUri:(NSString*)url{
    
    if(url){
        if(_requestQueue && _requestQueue.count == 1 && _backQueue && _backQueue.count >0 ){
            NSLog(@"");
        }else{
            [self removeObjectByKey:url];
        }
       
    }
    
    if(flowNo){
        [_backQueue removeObjectForKey:flowNo];
    }
}


#pragma mark--SRWebSocketDelegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
    NSString * url = [webSocket.url absoluteString];
    if(_requestQueue){
        _requestQueue[url] = webSocket;
        [_reconnectQueue removeObjectForKey:url];
    }
    if(_bakData&&_bakData.count>0){
        [self sendData:webSocket];
    }
}
-(void)sendData:(SRWebSocket *)webSocket{
    AWWeakSelf(self)
    [_bakData.allKeys enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [weakself dealWithBakData:obj webSocket:webSocket];
    }];
}

-(void)dealWithBakData:(NSString*)key webSocket:(SRWebSocket *)webSocket{
    NSString * url = [webSocket.url absoluteString];
    if( key && url){
        JFRequestVo * reqParamVo = _bakData[key];
        if(reqParamVo.reqParam && [url isEqualToString: reqParamVo.baseUri]){//发送数据
            [webSocket send:[reqParamVo.reqParam JSONPrintedString]];
            AWWeakSelf(self)
            [weakself removeBakData:key];
        }
    }
}
-(void)removeBakData:(NSString*)key{
    if(key){
        [_bakData removeObjectForKey:key];
    }
}
//连接失败，打印错误信息
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
    NSString * url = [webSocket.url absoluteString];
    NSNumber * number = _reconnectQueue[url];
    double delayInSeconds = 1.0;
    if(number){
        NSInteger reconnectNumber = [number integerValue];
        reconnectNumber++;
        _reconnectQueue[url] = @(reconnectNumber);
        if(reconnectNumber == 5){
            delayInSeconds = 5.0;
        }
    }else{
        if(url){
            _reconnectQueue[url] = @(1);
        }
    }
    //超过重连次数直接移除
    number = _reconnectQueue[url];
    if([number integerValue]>6){//重连了6次以上直接移除掉
        if(url){
            [_reconnectQueue removeObjectForKey:url];
            [self removeObjectByKey:url];
        }
    }else{
        [self removeObjectByKey:url];//先移除再次创建
        [self creatWebSocket:url];
    }
}
//接收服务器发送信息
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
    NSString * url = [webSocket.url absoluteString];
    NSString * dataParserName = _dataParserQueue[url];
    JFResultVo * result = nil;
    if(dataParserName){
        Class class = NSClassFromString(dataParserName);
        if([class respondsToSelector:@selector(dataParser:dataParserType: requestVo:)]){
            result = [class dataParser:message dataParserType:DataParserType_WebSocket requestVo:nil];
        }else if ([class respondsToSelector:@selector(dataParser:dataParserType:)]){
            result = [class dataParser:message dataParserType:DataParserType_WebSocket];
        }else{
            result = [JFDataParserHelper dataParser:message dataParserType:DataParserType_WebSocket requestVo:nil];
        }
        
    }else{
        result = [JFDataParserHelper dataParser:message dataParserType:DataParserType_WebSocket requestVo:nil];
    }
    if(!result){
        return;
    }
    
    if(result.flowNo){
        JFCallBack callback = _backQueue[result.flowNo];
        if(callback){
            callback(result);
        }
    }
}
// 长连接关闭
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
     NSString * url = [webSocket.url absoluteString];
     [self removeObjectByKey:url];//服务器关闭直接移除websocket
     [_requestQueue removeObjectForKey:url];
     [_dataParserQueue removeObjectForKey:url];
     [_reconnectQueue removeObjectForKey:url];
}
//该函数是接收服务器发送的pong消息
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
    NSData * data = [[NSData alloc]init];
    [webSocket sendPing:data];
}
#pragma mark--辅助方法
-(void)removeObjectByKey:(NSString*)key{
    if(_requestQueue && key){
        SRWebSocket * webSocket = _requestQueue[key];
        if(webSocket.readyState == SR_OPEN){
            [webSocket close];
        }
        if(webSocket){
            webSocket.delegate = nil;
            webSocket = nil;
        }
        [_requestQueue removeObjectForKey:key];
    }
}
@end
